
#include <BMouseEvent>
#include <BRender>
#include <BViewer>
#include <BScene>
#include <BShape>
#include <BTerrain>

#include "ConvertHandler.h"

ConvertHandler::ConvertHandler()
{
	_areaShown = false;
	_hovering = false;
	_pressed = false;
}
ConvertHandler::~ConvertHandler()
{

}

BLineArray& ConvertHandler::lostLines()
{
	return _lostLines;
}

void ConvertHandler::setNode(BNode* node)
{
	_node = node;
}
BNode* ConvertHandler::node() const
{
	return _node;
}

void ConvertHandler::setArea(const BSpace& area)
{
	_area = area;
}
const BSpace& ConvertHandler::area() const
{
	return _area;
}

void ConvertHandler::showArea()
{
	_areaShown = true;
	this->fresh();
}
void ConvertHandler::hideArea()
{
	_areaShown = false;
	this->fresh();
}

void ConvertHandler::drawPolyItem(const PolysOctItem& item, BRender& render)
{
	if (item.empty())
		return;

	const BTriangleArray& triangles = item->triangles;
	for (int i = 0; i < triangles.size(); i++)
	{
		render.fillTriangle(triangles[i]);
	}

	const BQuadArray& quads = item->quads;
	for (int i = 0; i < quads.size(); i++)
	{
		render.fillQuad(quads[i]);
	}

	const BPolygonArray& polygons = item->polygons;
	for (int i = 0; i < polygons.size(); i++)
	{
		render.drawPolygon(polygons[i]);
	}

}
void ConvertHandler::drawQuadItem(const QuadTreeItem& item, BRender& render)
{
	const BVectorArray* vertices = _hitTerrain->vertices();
	for (int i = 0; i < item->size(); i+=4)
	{
		int ia = item->at(i);
		int ib = item->at(i + 1);
		int ic = item->at(i + 2);
		int id = item->at(i + 3);
		const BVector& va = vertices->at(ia);
		const BVector& vb = vertices->at(ib);
		const BVector& vc = vertices->at(ic);
		const BVector& vd = vertices->at(id);
		render.fillQuad(va, vb, vc, vd);
	}
}

void ConvertHandler::paint(BPainter& painter)
{

}
void ConvertHandler::render(BRender& render)
{
	if (!_node)
		return;

	if (_areaShown)
	{
		const BSpace& space = _node->space();

		render.setLighting(false);
		render.setDepthTest(true);
		render.setColor(255, 255, 255, 100);
		if (_hovering)
			render.setColor(255, 255, 0, 100);
		if (_pressed)
			render.setColor(255, 255, 0, 160);
		render.fillQuad(_area.v4(), _area.v5(), _area.v6(), _area.v7());
		render.setColor(255, 255, 255);
		render.drawSpace(space);

		BReal width = space.width();
		BReal height = space.height();
		BVector v0(-width, -height, 0);
		BVector v1(width, -height, 0);
		BVector v2(width, height, 0);
		BVector v3(-width, height, 0);
		render.setColor(255, 255, 255, 160);
		render.drawQuad(v0, v1, v2, v3);
	}
	else
	{
		if (_hitPolyItems.size())
		{
			render.pushMatrix(BVector(0, 0, _area.depth() * 0.1f));
			for (int i = 0; i < _hitPolyItems.size(); i++)
			{
				PolysOctItem& item = _hitPolyItems[i];
				render.setLighting(false);
				render.setColor(200, 100, 100);
				render.drawSpace(item.space());
				render.setLighting(true);
				drawPolyItem(item, render);
			}
			render.popMatrix();
		}
		if (_hitQuadItems.size())
		{
			render.pushMatrix(BVector(0, 0, _area.depth() * 0.1f));
			for (int i = 0; i < _hitQuadItems.size(); i++)
			{
				QuadTreeItem& item = _hitQuadItems[i];
				render.setLighting(false);
				render.setColor(200, 100, 100);
				render.drawSpace(item.space());
				render.setLighting(true);
				drawQuadItem(item, render);
			}
			render.popMatrix();
		}
	}

	render.setLighting(false);
	render.setColor(255, 0, 255);
	render.drawLines(_lostLines.data(), _lostLines.size());
}

void ConvertHandler::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	BRoundHandler::mouseEnterEvent(mouseEvent);
	_hovering = false;
	this->fresh();
}
void ConvertHandler::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	BRoundHandler::mouseLeaveEvent(mouseEvent);
	_hovering = false;
	this->fresh();
}
void ConvertHandler::mousePressEvent(const BMouseEvent& mouseEvent)
{
	BRoundHandler::mousePressEvent(mouseEvent);
	if (mouseEvent.button() == Button_Left)
	{
		if (_hovering)
		{
			_pressed = true;
			_pressedPoint = _hoverPoint;
			_pressedArea = _area;
		}
		this->fresh();
	}
}
void ConvertHandler::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	BRoundHandler::mouseReleaseEvent(mouseEvent);
	if (mouseEvent.button() == Button_Left)
	{
		_pressed = false;
	}
}
void ConvertHandler::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	if (!_node)
		return;

	const BPoint& pos = mouseEvent.pos();
	BLine line = this->viewer()->line(pos);
	if (_areaShown)
	{
		const BSpace& space = _node->space();

		BQuad quad(_area.v4(), _area.v5(), _area.v6(), _area.v7());
		if (_pressed)
		{
			BPlane plane(quad.normal(), quad.a());
			BVector point;
			if (line.intersect(plane, point))
			{
				BVector offset = point - _pressedPoint;
				_area = _pressedArea + offset;
				_area = space.wrap(_area);
				emit("area-adjusted", _area);
				this->fresh();
			}
		}
		else if (mouseEvent.button() == Button_None)
		{
			bool hovering = line.intersect(quad, _hoverPoint);
			if (_hovering != hovering)
			{
				_hovering = hovering;
				if (_hovering)
					this->viewer()->setCursor(Cursor_SizeAll);
				else
					this->viewer()->setCursor(Cursor_None);
				this->fresh();
			}
		}
	}
	else
	{
		for (int i = 0; i < _node->shapeCount(); i++)
		{
			BShape* shape = _node->shape(i);
			if (BTerrain* terrain = dynamic_cast<BTerrain*>(shape))
			{
				_hitTerrain = 0;
				BValue value;
				if (terrain->query("quadtree", value))
				{
					QuadTree* quadTree = value;
					_hitTerrain = terrain;
					quadTree->intersect(line, _hitQuadItems);
					this->fresh();
				}
				break;
			}
			if (BGeometry* geometry = dynamic_cast<BGeometry*>(shape))
			{
				BValue value;
				if (geometry->query("polytree", value))
				{
					PolysOctTree* polyTree = value;
					polyTree->intersect(line, _hitPolyItems);
					this->fresh();
				}
				continue;
			}
		}
	}
	BRoundHandler::mouseMoveEvent(mouseEvent);
}
